package org.example;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;

import java.util.Vector;
import java.util.concurrent.locks.LockSupport;

@Slf4j
public class Main {

    //偏向锁撤销的第一种情况, 调用对象的hashcode时
    public static void main2(String[] args) throws InterruptedException {
        Dog d = new Dog();
        //会禁用对象的偏向锁
        d.hashCode();
        log.debug(ClassLayout.parseInstance(d).toPrintableSimple());

        synchronized (d){
            log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
        }
        log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
    }

    //偏向撤销的第二种情况： 当有其他线程访问对象时,偏向锁会被撤销
    public static void main3(String[] args) {
        Dog d = new Dog();

        new Thread(()->{
            log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
            synchronized (d){
                log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
            }
            log.debug(ClassLayout.parseInstance(d).toPrintableSimple());

            synchronized (Main.class){
                Main.class.notify();
            }
        }, "t1").start();

        new Thread(()->{
            synchronized (Main.class){
                try {
                    Main.class.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
            synchronized (d){
                log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
            }
            log.debug(ClassLayout.parseInstance(d).toPrintableSimple());
        }, "t1").start();
    }

    //偏向撤销的第三种情况： 调用wait/notify方法


    //批量重偏向

    //如果对象被多个线程访问时, 但没有竞争, 这时偏向了t1线程的对象仍有机会重新偏向t2,重偏向会重置markWord的threadID

    //当撤销偏向锁阈值超过20次后,jvm就会觉得偏向错了,于是乎,会在给这个对象加锁时, 重新偏向至加锁线程
    public static void main4(String[] args) throws InterruptedException {
        Vector<Dog> list = new Vector<>();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                Dog d = new Dog();
                list.add(d);
                synchronized (d) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                }
            }
            synchronized (list) {
                list.notify();
            }
        }, "t1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (list) {
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.debug("===============> ");
            for (int i = 0; i < 30; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                synchronized (d) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                }
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
            }
        }, "t2");
        t2.start();
    }

    //当撤销偏向锁阈值超过 40 次后，jvm 会这样觉得，自己确实偏向错了，根本就不该偏向。于是整个类的所有对象
    //都会变为不可偏向的，新建的对象也是不可偏向的
    static Thread t1,t2,t3;
    public static void main(String[] args) throws InterruptedException {
        Vector<Dog> list = new Vector<>();
        int loopNumber = 39;
        t1 = new Thread(() -> {
            for (int i = 0; i < loopNumber; i++) {
                Dog d = new Dog();
                list.add(d);
                synchronized (d) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                }
            }
            LockSupport.unpark(t2);
        }, "t1");
        t1.start();
        t2 = new Thread(() -> {
            LockSupport.park();
            log.debug("===============> ");
            for (int i = 0; i < loopNumber; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                synchronized (d) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                }
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
            }
            LockSupport.unpark(t3);
        }, "t2");

        t2.start();
        t3 = new Thread(() -> {
            LockSupport.park();
            log.debug("===============> ");
            for (int i = 0; i < loopNumber; i++) {
                Dog d = list.get(i);
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                synchronized (d) {
                    log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
                }
                log.debug(i + "\t" + ClassLayout.parseInstance(d).toPrintableSimple());
            }
        }, "t3");
        t3.start();
        t3.join();
        log.debug(ClassLayout.parseInstance(new Dog()).toPrintableSimple(true));
    }
}

class Dog{

}